package com.heima.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.LoginDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.user.mapper.ApUserMapper;
import com.heima.user.service.ApUserService;
import com.heima.user.utils.SendSms;
import com.heima.utils.common.AppJwtUtil;
import com.heima.utils.common.ValidateCodeUtils;
import org.apache.commons.codec.cli.Digest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

@Service
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements ApUserService {

    @Autowired
    private RedisTemplate redisTemplate;



    /**
     * app端登录
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult login(LoginDto dto) {
        //1.用户不为空，正常登录
        if (StringUtils.isNoneBlank(dto.getPhone()) && StringUtils.isNoneBlank(dto.getPassword())) {
            //1.1通过用户名获取用户
           /* LambdaQueryWrapper<ApUser> lqw = new LambdaQueryWrapper<>();
            lqw.eq(ApUser::getPhone,dto.getPhone());
            ApUser user = this.getOne(lqw);*/
            ApUser user = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));
            //1.2判断 如果用户不存在，则返回前端用户不存在
            if (user == null) {
                //如果用户不存在，则返回前端用户不存在
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在");
            }
            //2.如果用户存在 则比对密码 和 携带的token
            //2.1 将前端传过来的密码 和 数据库查到的用户的随机盐 组合后 MD5
            String pswd = dto.getPassword();//前端密码
            String salt = user.getSalt(); //盐
            pswd = DigestUtils.md5DigestAsHex((pswd + salt).getBytes());
            //比对密码
            if (!pswd.equals(user.getPassword())){
                //如果不匹配 则返回 登录失败 密码不匹配
                return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
            }
            //如果密码匹配 生成token 和查到的对象一起返回给前端
            Map<String,Object> map = new HashMap<>();
            map.put("token", AppJwtUtil.getToken(user.getId().longValue()));
            //返回查询对象的时候注意消除敏感信息
            user.setPassword(""); //消除密码
            user.setSalt("");     //消除盐
            map.put("user",user);
            return ResponseResult.okResult(map);
        }else {
            //2.用户没有输入账户密码 游客登录直接返回一个token就行 后续网关过滤器会进行判断
            Map<String,Object> map = new HashMap<>();
            map.put("token", AppJwtUtil.getToken(0L));
            return ResponseResult.okResult(map);
        }
    }

    /**
     * 用户注册时获取短信
     * @param dto
     * @param session
     * @return
     */
    @Override
    public ResponseResult sendMsg(LoginDto dto, HttpSession session) {
        //定义变量记录次数
        int count =0;
        //获取手机号
        String phone = dto.getPhone();
        //还需要判断是不是11位的数字
        Pattern pattern = Pattern.compile("^1[3|4|5|7|8][0-9]{9}$");
        if (!pattern.matcher(phone).matches()){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"请填写正确的手机号码");
        }
        if (StringUtils.isNotBlank(phone)) {
            //生成随机的4位验证码
            String code = ValidateCodeUtils.generateValidateCode4String(4);
            //调用工具发送短信
            SendSms.sendMsg(phone,code);
            //将生成的验证码和手机号缓存到Redis中，并且设置有效期为1分钟
            redisTemplate.opsForValue().set(code, code, 60, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(phone, phone, 60, TimeUnit.SECONDS);
            //定义一个变量 记录一个手机号获取短信的次数 注册时 超过三次 就返回其他的验证方式
            count++;
            redisTemplate.opsForValue().set(phone+"count",count,24,TimeUnit.HOURS);
            return ResponseResult.okResult("手机验证码短信发送成功");
        }
        return ResponseResult.okResult("手机验证码短信发送失败");
    }

    /**
     * 用户提交注册
     * @param map
     * @return
     */
    @Override
    public ResponseResult regist(Map<String, Object> map) {
        //1.获取map中包含 手机phone和短信code
        String phone = map.get("phone").toString();
        String code = map.get("code").toString();
        String strcount = redisTemplate.opsForValue().get(phone + "count").toString();
        int count = Integer.parseInt(strcount);
        //如果验证失败了3次 则更换验证方式（最好是绑定IP来验证失败次数）
        if (3 <= count){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"超过失败验证次数,更换滑块验证");
        }
        //如果没有则继续验证
        //2.传过来的手机为空 或者根据和获取验证码时的手机不一致
        if (StringUtils.isBlank(phone) || redisTemplate.opsForValue().get(phone)==null){
            //手机号不匹配 则返回重新输入手机号
            redisTemplate.opsForValue().getAndSet(phone+"count",++count);
            String strcount2 = redisTemplate.opsForValue().get(phone + "count").toString();
            return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR,"账号有误");
        }
        //3.从redis中获取数据
        Object redisCode = redisTemplate.opsForValue().get(code);
        //3.1如果传过来的短信为空，或者从redis中获取code时，如果过期 则提醒“已过期，请重新获取”
        if (redisCode==null || !code.equals(redisCode)){
            redisTemplate.opsForValue().getAndSet(phone+"count",++count);
            return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR,"验证码有误");
        }

        //如果没有问题则返回注册成功，前端跳转登录页面。
        return ResponseResult.okResult("注册成功");
    }
}
